//
//  Net.m
//  SceamingTimmy
//
//  Created by Yanjie Chen on 9/19/11.
//  Copyright 2011 Yanjie Chen. All rights reserved.
//

#import "Net.h"

@implementation Address

@synthesize address = _address;
@synthesize port = _port;

- (id)init {
	if( ( self = [super init] ) ) {
		_address = 0x7f000001;
		_port = 20000;
	}
	return self;
}

- (id)initWithAddress:(uint)address port:(ushort)port {
	if( ( self = [super init] ) ) {
		_address = address;
		_port = port;
	}
	
	return self;
}

- (id)initWithA:(unsigned char)a B:(unsigned char)b C:(unsigned char)c D:(unsigned char)d port:(ushort)port {
	if( ( self = [super init] ) ) {
		_address = ( a << 24 ) | ( b << 16 ) | ( c << 8 ) | d;
		_port = port;
	}
	
	return self;
}

- (unsigned char)getA {
	return ( unsigned char )( ( _address >> 24 ) & 0xFF );
}

- (unsigned char)getB {
	return ( unsigned char )( ( _address >> 16 ) & 0xFF );
}

- (unsigned char)getC {
	return ( unsigned char )( ( _address >> 8 ) & 0xFF );
}

- (unsigned char)getD {
	return ( unsigned char )( ( _address ) );
}

-(void)setA:(unsigned char)a{
    _address = (_address & 0xFFFFFF) | (a << 24);
}

-(void)setB:(unsigned char)b {
    _address = (_address & 0xFF00FFFF) | (b << 16);
}

-(void)setC:(unsigned char)c {
    _address = (_address & 0xFFFF00FF) | (c << 8);
}

-(void)setD:(unsigned char)d {
    _address = (_address & 0xFFFFFF00) | d;
}

-(void)changePortTo:(ushort)port {
    self.port = port;
}

- (void)dealloc {
	[super dealloc];
}

@end

@implementation Socket

- (id)init {
	if( ( self = [super init] ) ) {
		_socket = 0;
	}
	
	return self;
}

- (BOOL)open:(ushort)port {
	if( ![self isOpen] ) {
		_socket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
		
		if( _socket <= 0 ) {
			_socket = 0;
			return NO;
		}
		
		struct sockaddr_in addr;
		addr.sin_family	= AF_INET;
		addr.sin_addr.s_addr = INADDR_ANY;
		addr.sin_port = htons( port );
		
		if( bind( _socket, ( const struct sockaddr * )&addr, sizeof( struct sockaddr_in ) ) < 0 ) {
			[self close];
			return NO;
		}
		
		int nonBlocking = 1;
		if( fcntl( _socket, F_SETFL, O_NONBLOCK, nonBlocking ) == -1 ) {
			[self close];
			return NO;
		}
		
		return YES;
	}
	
	return NO;
}

- (BOOL)isOpen {
	return _socket != 0;
}

- (void)close {
	if( _socket ) {
		close( _socket );
		_socket = 0;
	}
}

- (BOOL)sendTo:(const Address *)addr data:(const char *)data size:(int)size {
	if( _socket == 0 || addr == nil ) {
		return NO;
	}
	
	struct sockaddr_in toAddr;
	toAddr.sin_family = AF_INET;
	toAddr.sin_addr.s_addr = htonl( addr.address );
	toAddr.sin_port = htons( addr.port );
	
	int sent_bytes = sendto( _socket, ( void * )data, size, 0, ( const struct sockaddr * )&toAddr, sizeof( struct sockaddr_in ) );
	
	return sent_bytes == size;
}

- (int)receiveFrom:(Address *)addr data:(char *)data size:(int)size {
	if( _socket == 0 || addr == nil || data == nil ) {
		return 0;
	}
	
	struct sockaddr_in from;
	socklen_t fromLen = sizeof( from );
	
	int received_bytes = recvfrom( _socket, ( void * )data, size, 0, ( struct sockaddr * )&from, &fromLen );
	
	uint address = ntohl( from.sin_addr.s_addr );
	ushort port = ntohs( from.sin_port );
	
	addr.address = address;
	addr.port = port;
	
	return received_bytes;
}

- (void)dealloc {
	[self close];
	[super dealloc];
}

@end


@implementation Net

@end
